<?php

use core\{DB, Session, Url};

/**
 * 获取请求数据，默认已过滤 html 标签等。
 */
function post($field_name, $clean_up = true)
{
    $value = $_POST[$field_name] ?? '';

    if ($clean_up) {
        $value = escape($value);

        if (is_numeric($value)) {
            $value = strpos($value, '.') !== false ? (double)$value : (int)$value;
        }
    }

    return $value;
}

/**
 * 获取一个数据表操作对象
 *
 * @param  string $table  数据表名称
 * @param  string $item   默认 db , 对应的数据库一级2配置名称
 * @return object         数据库操作对象
 */
function db($table, $item = 'db'): object
{
    $conf = config($item);
    return DB::getInstance($conf, $table, $item);
}

/**
 * 功能 : 获取一个模型
 *
 * @param  string $modelName  模型名称
 * @return object             模型对象
 * @throws Exception         如果模型不存在或文件名不合法
 */
function model(string $name): object
{
    $modelFile = APP_PATH. $name . '/models/' . ucfirst($name).'.php';

    // 确保模型文件存在
    if (!file_exists($modelFile)) {
        throw new Exception("模型文件 {$modelFile} 不存在");
    }

    require_once $modelFile;

    $modelName = '\\app\\' . $name . '\\models\\' . ucfirst($name);

    if (class_exists($modelName)) {
        return new $modelName();
    } else {
        throw new Exception("模型 {$modelName} 不存在");
    }
}


/**
 * 读取配置
 */
function config($key = null)
{
    static $conf = null;

    if ($conf === null) {
        $conf = include ROOT_PATH . 'config/app.php';
        if (!is_array($conf)) {
            throw new Exception('未能加载配置文件 config/app.php');
        }
    }

    if ($key === null) {
        return $conf;
    }

    // 处理点分割的键
    if (strpos($key, '.') !== false) {
        $keys = explode('.', $key, 2); // 限制分割成两部分
        if (isset($conf[$keys[0]][$keys[1]])) {
            return $conf[$keys[0]][$keys[1]];
        }
        return null;
    }

    // 处理单个键
    return isset($conf[$key]) ? $conf[$key] : null;
}

/**
 * 加载视图
 *
 * @param  string $path  视图文件路径
 * @param  array  $data  分配的变量
 * @return string
 */
function view(string $path, array $data = []): string
{
    $path = str_replace('.', '/', $path);
    $path = explode('/', $path);

    $file = realpath(APP_PATH . $path[0] . '/views/' . $path[1] . '.php');

    if (!$file || !file_exists($file) || is_dir($file)) {
        throw new Exception("模板文件 {$path[0]}/{$path[1]}.php 不存在");
    }

    extract($data, EXTR_REFS);

    ob_start();
    try {
        include($file);
    } catch (\Throwable $th) {
        trigger_error($th);
    }
    $contents = ob_get_contents() ?: '';
    ob_end_flush();

    return $contents;
}

function layout(string $template)
{
    $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
    // $this->layouts[realpath($backtrace[0]['file'])] = $template;
    return realpath($backtrace[0]['file']);
}

/**
 * 获取特定的 url 段
 *
 * @param int $num 要检索的段编号。
 * @param string|null $var_type （可选）设置段值的数据类型。默认值为null。
 * @return mixed 指定 url 段的值
 */
function setment(int $num, $var_type = null)
{
    if (array_key_exists('REQUEST_URI', $_SERVER) && is_string($_SERVER['REQUEST_URI'])) {
        $url = $_SERVER['REQUEST_URI'];
    } else {
        return [];
    }

    $url = ltrim($url, '/');
    $segments = explode('/', $url);
    $segments = array_map('escape', $segments);

    if (isset($segments[$num])) {
        $value = $segments[$num];
    } else {
        $value = '';
    }

    if ($var_type !== null) {
        settype($value, $var_type);
    }

    return $value;
}

function is_post()
{
    return strtolower($_SERVER['REQUEST_METHOD']) === 'post';
}

function is_get()
{
    return strtolower($_SERVER['REQUEST_METHOD']) === 'get';
}

/**
 * 获取当前页 URL
 *
 * @return string 当前页 URL
 */
function current_url() {
    $current_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] .  $_SERVER['REQUEST_URI'];
    return $current_url;
}

/**
 * 获取上一页的 URL（如果可用）。
 *
 * @return string 上一页 URL，如果不存在则返回空字符串
 */
function previous_url() {
    if (isset($_SERVER['HTTP_REFERER'])) {
        $url = $_SERVER['HTTP_REFERER'];
    } else {
        $url = '';
    }
    return $url;
}

/**
 * 友好的时间显示
 */
function nice_time($time) {
    $timeDiff = time() - $time;

    // 时间单位（秒）和对应的描述
    $units = [
        31536000 => '年',
        2592000  => '个月',
        604800   => '周',
        86400    => '天',
        3600     => '小时',
        60       => '分钟',
        1        => '秒'
    ];

    foreach ($units as $seconds => $unit) {
        if ($timeDiff >= $seconds) {
            $count = floor($timeDiff / $seconds);
            return $count . '<span class="time-text">' . $unit . '前</span>';
        }
    }

    // 如果由于某种原因没有返回任何值，可以添加一个默认返回值
    return '<span class="time-text">未知时间</span>';
}

/**
 * 格式化文件大小
 *
 * @param  int|float $size 文件大小（字节）
 * @param  int $precision 保留的小数位数
 * @return string 格式化的文件大小
 */
function format_size($size, $precision = 2)
{
    // 定义单位数组
    $units = [' 字节', ' KB', ' MB', ' GB', ' TB'];

    // 通过除以 1024 来找到合适的单位
    for ($i = 0; $size > 1024 && $i < 4; $i++) {
        $size /= 1024;
    }

    // 返回格式化的文件大小
    return round($size, $precision) . $units[$i];
}

/**
 * 生成一个指定长度的唯一ID（类似于UUID）
 *
 * @param int $length 生成ID的长度，默认为20
 * @return string 返回生成的唯一ID字符串
 */
function uuid(int $length = 20): string {
    $bytes = random_bytes((int)ceil($length / 2));
    return substr(bin2hex($bytes), 0, $length);
}

/**
 * 转义恶意字符
 *
 * @param mixed $data 要清除的数据
 */
function sanitize($data)
{
    if (is_array($data)) {
        foreach ($data as $key => $value) {
            $data[is_string($key) ? escape($key) : $key] = escape($value);
        }
    }

    if (is_string($data)) {
        $data = escape($data);
    }

    return $data;
}

/**
 * 过滤和清理字符串，转义 HTML 特殊字符
 *
 * @param  string $value 要过滤的值
 * @return string 过滤后的值，保持与输入相同的类型
 * @throws TypeError 如果输入的值类型不是字符串
 */
function escape(string $value): string
{
    return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

/**
 * 确认目录存在
 *
 * @param string $path
 */
function path_sure(string $path)
{
    if (!file_exists($path)) {
        mkdir($path, 0777, true);
    }
}

/**
 * 获取完整 uri
 * @return string
 * @example http://xxx.com|https://xxx.com|http://xxx.com:88|https://xxx.com:88
 */
function uri_full()
{
    $pageURL = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
    $pageURL .= $_SERVER['HTTP_HOST'];

    return $pageURL;
}

/**
 * 获取请求IP
 *
 * @return string 客户端的IP地址
 */
function get_ip() {
    if (isset($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] !== 'unknown') {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] !== 'unknown') {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] !== 'unknown') {
        $ip = $_SERVER['REMOTE_ADDR'];
    } else {
        $ip = '127.0.0.1';
    }

    // 使用正则表达式过滤IP地址，如果匹配成功则返回匹配到的第一个IP，否则返回127.0.0.1
    return preg_match('/[\d\.]{7,15}/', $ip, $matches) ? $matches[0] : '127.0.0.1';
}

/**
 * 对指定的 URL 执行 HTTP 重定向。
 *
 * @param  string $target_url 重定向应指向的URL
 * @param  int  $status
 */
function redirect(string $target_url, int $status = 302)
{
    $url = filter_var($target_url, FILTER_SANITIZE_URL);
    header('Location: ' . $url, true, $status);
    die();
}

function session(string $key)
{
    return Session::has($key) ? Session::get($key) : false;
}

function url(string $path = ''): string
{
    return Url::home() . filter_var($path, FILTER_SANITIZE_URL);
}

/**
 * 输出 json
 *
 * @param string $msg    提示内容
 * @param string $status 状态，默认是错误，还可设置为 'success'
 */
function json(string $msg, string $status = 'error')
{
    // header('Content-Type: application/json; charset=utf-8');
    echo json_encode(
        [
            'message' => escape($msg),
            'status'  => $status
        ],
        JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE
    );
}

/**
 * 取得文件扩展名
 *
 * @param string $filename 文件名
 * @return string 扩展名
 */
function file_ext($filename) {
    $parts = explode('.', $filename);
    $ext = end($parts);

    return strtolower($ext);
}

function processMarkdownFiles($directory, $maxDepth = 3, $currentDepth = 0) {
    // 检查目录是否可读且是目录
    if (!is_dir($directory) || !is_readable($directory)) {
        error_log("无法读取目录: $directory");
        return;
    }

    // 检查递归深度
    if ($currentDepth >= $maxDepth) {
        return;
    }

    // 获取目录中的文件和子目录
    $files = scandir($directory);

    foreach ($files as $file) {
        // 排除当前目录（.）和上级目录（..）
        if ($file == '.' || $file == '..') {
            continue;
        }

        $fullPath = realpath($directory . '/' . $file);

        // 如果是目录，则递归调用自身
        if (is_dir($fullPath)) {
            processMarkdownFiles($fullPath, $maxDepth, $currentDepth + 1);
        } elseif (pathinfo($fullPath, PATHINFO_EXTENSION) === 'md') {
            // 处理 .md 文件
            // 这里可以添加对文件的操作，例如读取内容、解析等
            echo "处理文件: $fullPath\n";
        }
    }
}

/**
 * 调试输出
 */
function dump(...$value): void
{
    ob_start();
    var_dump(...$value);
    $output = ob_get_clean();
    $output = preg_replace('/]=>\n(\s+)/m', '] => ', $output);
    $output = '<pre>' . htmlspecialchars($output, ENT_SUBSTITUTE) . '</pre>';
    echo $output;
}

/**
 * 输出并退出
 */
function dd(...$vars): void
{
    dump($vars);
    exit();
}
